#include <iostream>
using namespace std;
#include <string>
#include <cerrno>
#include <cstring>
// 这四个头文件是写套接字经常用到的
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void Usage(string proc)
{
    cout << "Usage: " << proc << " server_ip server_port " << endl;
}

// ./udp_client server_ip server_port

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 0;
    }
    // 1.创建套接字，打开网络文件,ipv4使用AF_INET, udp使用SOCK_DGRAM,协议为0
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cerr << "socket error :" << errno << endl;
        return 1;
    }
    // 客户端需要显示地bind吗？？
    // a.客户端必须要ip，port
    // b.但是，客户端不需要显示bind，一旦显示bind，就必须明确client 要和 哪个port关联
    // client 指明的端口号，在client端一定有吗？？有可能已经被占用了，就导致客户端无法使用
    // server端要的port必须明确且不变，但client只要有port就行
    // 一般OS自动bind，client正常发送数据时候，OS会自动bind，采用随机端口方式，所以不需要显示bind
    // 2.使用服务
    while (1)
    {
        /* // a.你要发送的数据从哪来？
        string message;
        cout << "发送消息：";
        cin >> message;  */
        char line[1024];
        cout << "Shell :> ";
        fgets(line, sizeof(line), stdin);
        // b.要把数据发送到哪里去？
        struct sockaddr_in server;              // 服务器信息
        server.sin_family = AF_INET;            // IPv4 协议
        server.sin_port = htons(atoi(argv[2])); // 先把字符串转整形，再把整形从主机序列转网络序列；
        server.sin_addr.s_addr = inet_addr(argv[1]);
        sendto(sock, line, strlen(line), 0, (struct sockaddr *)&server, sizeof(server));

        // 接收服务器信息和数据
        // 因为其实我们早就知道服务器信息了，所以这里的tmp起占位符作用
        struct sockaddr_in tmp;
        socklen_t len = sizeof(tmp);

        char buffer[1024];
        ssize_t s = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&tmp, &len);
        if (s > 0)
        {
            // 在网络通信中，只有报文大小，或者是字节流中字节的个数，没有C/C++字符串的概念
            buffer[s] = 0;
            cout << buffer << endl;
        }
        else
        {
            //
        }
    }

    return 0;
}